// popups2.cpp : Defines the entry point for the DLL application.
//

#include "common.h"
#include "tipper.h"
#include "../res/version.h"
#include "message_pump.h"
#include "options.h"
#include "popwin.h"
#include "str_utils.h"

HMODULE hInst = 0;
HANDLE mainThread = 0;

bool unicode_system;

FontID font_id_title = {0}, font_id_labels = {0}, font_id_values = {0};
ColourID colour_id_bg = {0}, colour_id_border = {0}, colour_id_divider = {0}, colour_id_sidebar = {0};
FontIDW font_id_titlew = {0}, font_id_labelsw = {0}, font_id_valuesw = {0};
ColourIDW colour_id_bgw = {0}, colour_id_borderw = {0}, colour_id_dividerw = {0}, colour_id_sidebarw = {0};

HFONT hFontTitle = 0, hFontLabels = 0, hFontValues = 0;

// hooked here so it's in the main thread
HANDLE hAvChangeEvent = 0, hShowTipEvent = 0, hHideTipEvent = 0, hAckEvent = 0, hFramesSBShow = 0, hFramesSBHide = 0, hSettingChangedEvent = 0;

HANDLE hShowTipService = 0, hShowTipWService = 0, hHideTipService = 0;

struct MM_INTERFACE memoryManagerInterface = {0};

PLUGININFOEX pluginInfo={
	sizeof(PLUGININFOEX),
	__PLUGIN_NAME,
	PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
	__DESC,
	__AUTHOR,
	__AUTHOREMAIL,
	__COPYRIGHT,
	__AUTHORWEB,
	UNICODE_AWARE,		//not transient
	0,					//doesn't replace anything built-in

#ifndef _UNICODE
{ 0xedae7137, 0x1b6a, 0x4b8f, { 0xaa, 0xb0, 0x3b, 0x5a, 0x2f, 0x8, 0xf4, 0x62 } } // {EDAE7137-1B6A-4b8f-AAB0-3B5A2F08F462}
#else
{ 0x785c25e3, 0xc906, 0x434b, { 0x97, 0x23, 0xe2, 0x44, 0xe1, 0xbe, 0xca, 0x2 } } // {785C25E3-C906-434b-9723-E244E1BECA02}
#endif
};

PLUGINLINK *pluginLink = 0;

extern "C" BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
	hInst = hModule;
	DisableThreadLibraryCalls(hInst);
    return TRUE;
}

extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
{
	return &pluginInfo;
}

extern "C" __declspec(dllexport) PLUGININFO* MirandaPluginInfo(DWORD mirandaVersion)
{
	pluginInfo.cbSize = sizeof(PLUGININFO);
	return (PLUGININFO*)&pluginInfo;
}

static const MUUID interfaces[] = {MIID_TOOLTIPS, MIID_LAST};
extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
{
	return interfaces;
}



int ReloadFont(WPARAM wParam, LPARAM lParam) {

	if(ServiceExists(MS_FONT_GETW)) {
		LOGFONTW log_font;
		if(hFontTitle) DeleteObject(hFontTitle);
		options.title_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_titlew, (LPARAM)&log_font);
		hFontTitle = CreateFontIndirectW(&log_font);
		if(hFontLabels) DeleteObject(hFontLabels);
		options.label_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_labelsw, (LPARAM)&log_font);
		hFontLabels = CreateFontIndirectW(&log_font);
		if(hFontValues) DeleteObject(hFontValues);
		options.value_col = CallService(MS_FONT_GETW, (WPARAM)&font_id_valuesw, (LPARAM)&log_font);
		hFontValues = CreateFontIndirectW(&log_font);

		options.bg_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_bgw, 0);
		options.border_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_borderw, 0);
		options.sidebar_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_sidebarw, 0);
		options.div_col = CallService(MS_COLOUR_GETW, (WPARAM)&colour_id_dividerw, 0);
	} else {
		LOGFONTA log_font;
		if(hFontTitle) DeleteObject(hFontTitle);
		options.title_col = CallService(MS_FONT_GET, (WPARAM)&font_id_title, (LPARAM)&log_font);
		hFontTitle = CreateFontIndirectA(&log_font);
		if(hFontLabels) DeleteObject(hFontLabels);
		options.label_col = CallService(MS_FONT_GET, (WPARAM)&font_id_labels, (LPARAM)&log_font);
		hFontLabels = CreateFontIndirectA(&log_font);
		if(hFontValues) DeleteObject(hFontValues);
		options.value_col = CallService(MS_FONT_GET, (WPARAM)&font_id_values, (LPARAM)&log_font);
		hFontValues = CreateFontIndirectA(&log_font);

		options.bg_col = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_bg, 0);
		options.border_col = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_border, 0);
		options.sidebar_col = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_sidebar, 0);
		options.div_col = CallService(MS_COLOUR_GET, (WPARAM)&colour_id_divider, 0);
	}

	return 0;
}

// hack to hide tip when clist hides from timeout
int SettingChanged(WPARAM wParam, LPARAM lParam) {
	DBCONTACTWRITESETTING *dcws = (DBCONTACTWRITESETTING *)lParam;
	if(strcmp(dcws->szModule, "CList") != 0 || strcmp(dcws->szSetting, "State") != 0) return 0;

	// clist hiding
	if(dcws->value.type == DBVT_BYTE && dcws->value.bVal == 0) {
		HideTip(0, 0);
	}

	return 0;
}

int ModulesLoaded(WPARAM wParam, LPARAM lParam) {
	if(ServiceExists(MS_UPDATE_REGISTER)) {
		// register with updater
		Update update = {0};
		char szVersion[16];

		update.cbSize = sizeof(Update);

		update.szComponentName = pluginInfo.shortName;
		update.pbVersion = (BYTE *)CreateVersionString(pluginInfo.version, szVersion);
		update.cpbVersion = strlen((char *)update.pbVersion);

		update.szUpdateURL = UPDATER_AUTOREGISTER;
		
		// these are the three lines that matter - the archive, the page containing the version string, and the text (or data) 
		// before the version that we use to locate it on the page
		// (note that if the update URL and the version URL point to standard file listing entries, the backend xml
		// data will be used to check for updates rather than the actual web page - this is not true for beta urls)
		update.szBetaUpdateURL = "http://www.scottellis.com.au/miranda_plugins/tipper.zip";
		update.szBetaVersionURL = "http://www.scottellis.com.au/miranda_plugins/ver_tipper.html";
		update.pbBetaVersionPrefix = (BYTE *)"Tipper version ";
		
		update.cpbBetaVersionPrefix = strlen((char *)update.pbBetaVersionPrefix);

		CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
	}

	if(ServiceExists(MS_FONT_REGISTERW)) {
		font_id_titlew.cbSize = sizeof(FontIDW);
		font_id_titlew.flags = FIDF_ALLOWEFFECTS;
		t2w(TranslateT("Tooltips"), font_id_titlew.group, 64);
		t2w(TranslateT("Title"), font_id_titlew.name, 64);
		strcpy(font_id_titlew.dbSettingsGroup, MODULE);
		strcpy(font_id_titlew.prefix, "FontFirst");
		font_id_titlew.order = 0;

		font_id_titlew.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_titlew.deffontsettings.size = -14;
		font_id_titlew.deffontsettings.style = DBFONTF_BOLD;
		font_id_titlew.deffontsettings.colour = RGB(255, 0, 0);
		font_id_titlew.flags |= FIDF_DEFAULTVALID;

		font_id_labelsw.cbSize = sizeof(FontIDW);
		font_id_labelsw.flags = FIDF_ALLOWEFFECTS;
		t2w(TranslateT("Tooltips"), font_id_labelsw.group, 64);
		t2w(TranslateT("Labels"), font_id_labelsw.name, 64);
		strcpy(font_id_labelsw.dbSettingsGroup, MODULE);
		strcpy(font_id_labelsw.prefix, "FontLabels");
		font_id_labelsw.order = 1;

		font_id_labelsw.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_labelsw.deffontsettings.size = -12;
		font_id_labelsw.deffontsettings.style = DBFONTF_ITALIC;
		font_id_labelsw.deffontsettings.colour = RGB(128, 128, 128);
		font_id_labelsw.flags |= FIDF_DEFAULTVALID;

		font_id_valuesw.cbSize = sizeof(FontIDW);
		font_id_valuesw.flags = FIDF_ALLOWEFFECTS;
		t2w(TranslateT("Tooltips"), font_id_valuesw.group, 64);
		t2w(TranslateT("Values"), font_id_valuesw.name, 64);
		strcpy(font_id_valuesw.dbSettingsGroup, MODULE);
		strcpy(font_id_valuesw.prefix, "FontValues");
		font_id_valuesw.order = 2;

		font_id_valuesw.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_valuesw.deffontsettings.size = -12;
		font_id_valuesw.deffontsettings.style = 0;
		font_id_valuesw.deffontsettings.colour = RGB(0, 0, 0);
		font_id_valuesw.flags |= FIDF_DEFAULTVALID;

		CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_titlew, 0);
		CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_labelsw, 0);
		CallService(MS_FONT_REGISTERW, (WPARAM)&font_id_valuesw, 0);
		
		colour_id_bgw.cbSize = sizeof(ColourIDW);
		t2w(TranslateT("Tooltips"), colour_id_bgw.group, 64);
		t2w(TranslateT("Background"), colour_id_bgw.name, 64);
		strcpy(colour_id_bgw.dbSettingsGroup, MODULE);
		strcpy(colour_id_bgw.setting, "ColourBg");
		colour_id_bgw.defcolour = RGB(219, 219, 219);
		colour_id_bgw.order = 0;

		colour_id_borderw.cbSize = sizeof(ColourIDW);
		t2w(TranslateT("Tooltips"), colour_id_borderw.group, 64);
		t2w(TranslateT("Border"), colour_id_borderw.name, 64);
		strcpy(colour_id_borderw.dbSettingsGroup, MODULE);
		strcpy(colour_id_borderw.setting, "BorderCol");
		colour_id_borderw.defcolour = 0;
		colour_id_borderw.order = 0;

		colour_id_dividerw.cbSize = sizeof(ColourIDW);
		t2w(TranslateT("Tooltips"), colour_id_dividerw.group, 64);
		t2w(TranslateT("Dividers"), colour_id_dividerw.name, 64);
		strcpy(colour_id_dividerw.dbSettingsGroup, MODULE);
		strcpy(colour_id_dividerw.setting, "DividerCol");
		colour_id_dividerw.defcolour = 0;
		colour_id_dividerw.order = 0;

		colour_id_sidebarw.cbSize = sizeof(ColourIDW);
		t2w(TranslateT("Tooltips"), colour_id_sidebarw.group, 64);
		t2w(TranslateT("Sidebar"), colour_id_sidebarw.name, 64);
		strcpy(colour_id_sidebarw.dbSettingsGroup, MODULE);
		strcpy(colour_id_sidebarw.setting, "SidebarCol");
		colour_id_sidebarw.defcolour = RGB(192, 192, 192);
		colour_id_sidebarw.order = 0;

		CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_bgw, 0);
		CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_borderw, 0);
		CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_dividerw, 0);
		CallService(MS_COLOUR_REGISTERW, (WPARAM)&colour_id_sidebarw, 0);
		
		ReloadFont(0, 0);

		HookEvent(ME_FONT_RELOAD, ReloadFont);
	} else if(ServiceExists(MS_FONT_REGISTER)) {
		font_id_title.cbSize = sizeof(FontID);
		font_id_title.flags = FIDF_ALLOWEFFECTS;
		t2a(TranslateT("Tooltips"), font_id_title.group, 64);
		t2a(TranslateT("Title"), font_id_title.name, 64);
		strcpy(font_id_title.dbSettingsGroup, MODULE);
		strcpy(font_id_title.prefix, "FontFirst");
		font_id_title.order = 0;

		font_id_title.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_title.deffontsettings.size = -14;
		font_id_title.deffontsettings.style = DBFONTF_BOLD;
		font_id_title.deffontsettings.colour = RGB(255, 0, 0);
		font_id_title.flags |= FIDF_DEFAULTVALID;

		font_id_labels.cbSize = sizeof(FontID);
		font_id_labels.flags = FIDF_ALLOWEFFECTS;
		t2a(TranslateT("Tooltips"), font_id_labels.group, 64);
		t2a(TranslateT("Labels"), font_id_labels.name, 64);
		strcpy(font_id_labels.dbSettingsGroup, MODULE);
		strcpy(font_id_labels.prefix, "FontLabels");
		font_id_labels.order = 1;

		font_id_labels.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_labels.deffontsettings.size = -12;
		font_id_labels.deffontsettings.style = DBFONTF_ITALIC;
		font_id_labels.deffontsettings.colour = RGB(128, 128, 128);
		font_id_labels.flags |= FIDF_DEFAULTVALID;

		font_id_values.cbSize = sizeof(FontID);
		font_id_values.flags = FIDF_ALLOWEFFECTS;
		t2a(TranslateT("Tooltips"), font_id_values.group, 64);
		t2a(TranslateT("Values"), font_id_values.name, 64);
		strcpy(font_id_values.dbSettingsGroup, MODULE);
		strcpy(font_id_values.prefix, "FontValues");
		font_id_values.order = 2;

		font_id_values.deffontsettings.charset = DEFAULT_CHARSET;
		font_id_values.deffontsettings.size = -12;
		font_id_values.deffontsettings.style = 0;
		font_id_values.deffontsettings.colour = RGB(0, 0, 0);
		font_id_values.flags |= FIDF_DEFAULTVALID;

		CallService(MS_FONT_REGISTER, (WPARAM)&font_id_title, 0);
		CallService(MS_FONT_REGISTER, (WPARAM)&font_id_labels, 0);
		CallService(MS_FONT_REGISTER, (WPARAM)&font_id_values, 0);
		
		colour_id_bg.cbSize = sizeof(ColourID);
		t2a(TranslateT("Tooltips"), colour_id_bg.group, 64);
		t2a(TranslateT("Background"), colour_id_bg.name, 64);
		strcpy(colour_id_bg.dbSettingsGroup, MODULE);
		strcpy(colour_id_bg.setting, "ColourBg");
		colour_id_bg.defcolour = RGB(219, 219, 219);
		colour_id_bg.order = 0;

		colour_id_border.cbSize = sizeof(ColourID);
		t2a(TranslateT("Tooltips"), colour_id_border.group, 64);
		t2a(TranslateT("Border"), colour_id_border.name, 64);
		strcpy(colour_id_border.dbSettingsGroup, MODULE);
		strcpy(colour_id_border.setting, "BorderCol");
		colour_id_border.defcolour = 0;
		colour_id_border.order = 0;

		colour_id_divider.cbSize = sizeof(ColourID);
		t2a(TranslateT("Tooltips"), colour_id_divider.group, 64);
		t2a(TranslateT("Dividers"), colour_id_divider.name, 64);
		strcpy(colour_id_divider.dbSettingsGroup, MODULE);
		strcpy(colour_id_divider.setting, "DividerCol");
		colour_id_divider.defcolour = 0;
		colour_id_divider.order = 0;

		colour_id_sidebar.cbSize = sizeof(ColourID);
		t2a(TranslateT("Tooltips"), colour_id_sidebar.group, 64);
		t2a(TranslateT("Sidebar"), colour_id_sidebar.name, 64);
		strcpy(colour_id_sidebar.dbSettingsGroup, MODULE);
		strcpy(colour_id_sidebar.setting, "SidebarCol");
		colour_id_sidebar.defcolour = RGB(192, 192, 192);
		colour_id_sidebar.order = 0;

		CallService(MS_COLOUR_REGISTER, (WPARAM)&colour_id_bg, 0);
		CallService(MS_COLOUR_REGISTER, (WPARAM)&colour_id_border, 0);
		CallService(MS_COLOUR_REGISTER, (WPARAM)&colour_id_divider, 0);
		CallService(MS_COLOUR_REGISTER, (WPARAM)&colour_id_sidebar, 0);
		
		ReloadFont(0, 0);

		HookEvent(ME_FONT_RELOAD, ReloadFont);
	} else {
		options.title_col = RGB(255, 0, 0); options.label_col = RGB(128, 128, 128), options.value_col = 0;
		options.bg_col = RGB(219, 219, 219);
		options.border_col = options.div_col = 0;
		options.sidebar_col = RGB(192, 192, 192);

		LOGFONT lf = {0};
		lf.lfCharSet = DEFAULT_CHARSET;
		lf.lfHeight = -14;
		lf.lfWeight = FW_BOLD;
		hFontTitle = CreateFontIndirect(&lf);

		lf.lfHeight = -12;
		lf.lfWeight = 0;
		lf.lfItalic = TRUE;
		hFontLabels = CreateFontIndirect(&lf);

		lf.lfHeight = -12;
		lf.lfWeight = 0;
		lf.lfItalic = FALSE;
		hFontValues = CreateFontIndirect(&lf);
	}

	hAvChangeEvent = HookEvent(ME_AV_AVATARCHANGED, AvatarChanged);
	hShowTipEvent = HookEvent(ME_CLC_SHOWINFOTIP, ShowTip);
	hHideTipEvent = HookEvent(ME_CLC_HIDEINFOTIP, HideTip);
	hAckEvent = HookEvent(ME_PROTO_ACK, ProtoAck);

	hFramesSBShow = HookEvent(ME_CLIST_FRAMES_SB_SHOW_TOOLTIP, FramesShowSBTip);
	hFramesSBHide = HookEvent(ME_CLIST_FRAMES_SB_HIDE_TOOLTIP, FramesHideSBTip);

	LoadOptions(); 

	// set 'time-in'
	CallService(MS_CLC_SETINFOTIPHOVERTIME, options.time_in, 0);

	return 0;
}

int Shutdown(WPARAM wParam, LPARAM lParam) {
	if(hFramesSBShow) UnhookEvent(hFramesSBShow);
	if(hFramesSBHide) UnhookEvent(hFramesSBHide);
	if(hAvChangeEvent) UnhookEvent(hAvChangeEvent);
	if(hShowTipEvent) UnhookEvent(hShowTipEvent);
	if(hHideTipEvent) UnhookEvent(hHideTipEvent);
	if(hAckEvent) UnhookEvent(hAckEvent);

	if(hShowTipService) DestroyServiceFunction(hShowTipService);
	if(hShowTipWService) DestroyServiceFunction(hShowTipWService);
	if(hHideTipService) DestroyServiceFunction(hHideTipService);

	DeinitMessagePump();

	return 0;
}

HANDLE hEventPreShutdown, hEventModulesLoaded;

extern "C" int TIPPER_API Load(PLUGINLINK *link) {
	pluginLink = link;
	DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &mainThread, THREAD_SET_CONTEXT, FALSE, 0);

	set_codepage();

	char szVer[128];
	unicode_system = (CallService(MS_SYSTEM_GETVERSIONTEXT, (WPARAM)sizeof(szVer), (LPARAM)szVer) == 0 && strstr(szVer, "Unicode"));

	// get the internal malloc/free()
	memoryManagerInterface.cbSize = sizeof(memoryManagerInterface);
	CallService(MS_SYSTEM_GET_MMI, 0, (LPARAM)&memoryManagerInterface);

	// don't save status messages
	CallService(MS_DB_SETSETTINGRESIDENT, (WPARAM)TRUE, (LPARAM)MODULE "/TempStatusMsg");

	// Ensure that the common control DLL is loaded (for listview)
	INITCOMMONCONTROLSEX icex;
	icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
	icex.dwICC  = ICC_LISTVIEW_CLASSES;
	InitCommonControlsEx(&icex); 	

	if(ServiceExists(MS_LANGPACK_GETCODEPAGE))
		code_page = CallService(MS_LANGPACK_GETCODEPAGE, 0, 0);

	InitTranslations();
	InitMessagePump();
	InitOptions();

	// for compatibility with mToolTip status tooltips
	hShowTipService = CreateServiceFunction("mToolTip/ShowTip", ShowTip);
	hShowTipWService = CreateServiceFunction("mToolTip/ShowTipW", ShowTipW);
	hHideTipService = CreateServiceFunction("mToolTip/HideTip", HideTip);

	hEventPreShutdown = HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown);
	hEventModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);

	hSettingChangedEvent = HookEvent(ME_DB_CONTACT_SETTINGCHANGED, SettingChanged);

	return 0;
}

extern "C" int TIPPER_API Unload() {
	UnhookEvent(hSettingChangedEvent);
	UnhookEvent(hEventPreShutdown);
	UnhookEvent(hEventModulesLoaded);

	DeinitOptions();
	if(ServiceExists(MS_FONT_REGISTERW)) {
		DeleteObject(hFontTitle);
		DeleteObject(hFontLabels);
		DeleteObject(hFontValues);
	} // otherwise, no need to delete the handle
	DeinitTranslations();
	return 0;
}
